package com.ruiyou.ub;

import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.CheckBox;
import android.widget.Toast;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class UWebView extends WebView implements View.OnLongClickListener {

    private UDownloadUtil downloadUtil;
    private final String SHARED_PREF = "web_view.sp";
    private final String KEY_DICT_JS = "enabled_dict_javascript";
    private boolean allowCallOtherApp = false;// 是否允许调用外部应用
    private boolean enabledDictJS;
    private boolean enabledFind = true;
    private String selText;
    private boolean isGotoFind;
    StateListener stateListener = null;

    public UWebView(Context context) {
        this(context, null);
    }

    public UWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
        readPreferences();
    }

    /**
     * 初始化WebView
     */
    private void initView() {
        downloadUtil = new UDownloadUtil(getContext());
        setDownloadListener(downloadUtil);
        setOnLongClickListener(this);
        setWebChromeClient(new UWebChromeClient(this));
        setWebViewClient(new UWebViewClient(this));
        getSettings().setBuiltInZoomControls(true);
        getSettings().setAllowFileAccess(true);
        getSettings().setDatabaseEnabled(true);
        getSettings().setDomStorageEnabled(true);
        getSettings().setUseWideViewPort(true);
    }

    public boolean getAllowCallOtherApp() {
        return allowCallOtherApp;
    }

    public void setAllowCallOtherApp(boolean allowCallOtherApp) {
        this.allowCallOtherApp = allowCallOtherApp;
    }

    // 加载偏好设置
    private void readPreferences() {
        SharedPreferences sp = getContext()
                .getSharedPreferences(SHARED_PREF, 0);
        enabledDictJS = sp.getBoolean(
                KEY_DICT_JS, false
        );
    }

    // 保存偏好设置
    private void savePreferences() {
        SharedPreferences sp = getContext()
                .getSharedPreferences(SHARED_PREF, 0);
        sp.edit()
                .putBoolean(KEY_DICT_JS, enabledDictJS)
                .apply();
    }

    /**
     * LongClick download picture
     *
     * @param v ...
     * @return ...
     */
    @Override
    public boolean onLongClick(View v) {
        final HitTestResult htr = this.getHitTestResult();
        if (htr.getExtra() == null || htr.getType() != HitTestResult.IMAGE_TYPE &&
                htr.getType() != HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
            return false;
        }
        Util.Callback callback = result -> {
            int which = Integer.parseInt(result);
            if (which == 0) {
                downloadUtil.downloadPicture(htr.getExtra());
            } else {
                Runnable runnable = () -> {
                    String str;
                    try {
                        InputStream is = new URL(htr.getExtra()).openStream();
                        Bitmap bmp = BitmapFactory.decodeStream(is);
                        str = Util.decodeQRCode(bmp);
                        is.close();
                    } catch (IOException e) {
                        str = e.getMessage();
                    }
                    String finalStr = str;
                    new Handler(Looper.getMainLooper()).post(() -> Util.showDialog(
                            getContext(),
                            getContext().getString(R.string.scanning_result),
                            finalStr,
                            DialogType.INFO,
                            null
                    ));
                };
                new Thread(runnable).start();
            }
        };
        Context context = getContext();
        Util.showDialog(
                context,
                context.getString(R.string.select_processor),
                context.getString(R.string.download_picture) + "," +
                        context.getString(R.string.scan_qr_code),
                DialogType.SELECT,
                callback
        );
        return true;
    }

    /**
     * Customize the popup menu
     *
     * @param callback 。。。
     * @param type     。。。
     * @return 。。。
     */
    @Override
    public ActionMode startActionMode(ActionMode.Callback callback, int type) {
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            ActionMode am = super.startActionMode(callback, type);
            customMenu(am.getMenu());
            return am;
        }
        return super.startActionMode(new ActionMode.Callback() {
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                return callback.onCreateActionMode(mode, menu);
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                boolean r = callback.onPrepareActionMode(mode, menu);
                customMenu(menu);
                return r;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                return callback.onActionItemClicked(mode, item);
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                callback.onDestroyActionMode(mode);
            }
        }, type);
    }

    private void customMenu(final Menu menu) {
//        final Menu menu = mode.getMenu();
        MenuItem copyItem = null;
        // if contains 'Copy'
        for (int i = 0; i < menu.size(); i++) {
            if (menu.getItem(i).getTitle().toString().equalsIgnoreCase(
                    getResources().getString(android.R.string.copy))) {
                copyItem = menu.getItem(i);
                break;
            }
        }
        if (copyItem == null) return;
        ClipboardManager cm = (ClipboardManager) getContext()
                .getSystemService(Context.CLIPBOARD_SERVICE);
        if (cm == null) {
            Toast.makeText(
                    getContext(),
                    "ERROR: Could not get ClipboardService!",
                    Toast.LENGTH_SHORT
            ).show();
            return;
        }
        ClipData oldClipData = cm.getPrimaryClip();
        ClipboardManager.OnPrimaryClipChangedListener clipListener =
                new ClipboardManager.OnPrimaryClipChangedListener() {
                    @Override
                    public void onPrimaryClipChanged() {
                        cm.removePrimaryClipChangedListener(this);
                        selText = cm.getPrimaryClip().getItemAt(0).getText().toString();
                        if (oldClipData != null) {
                            cm.setPrimaryClip(oldClipData);
                        } else {
                            cm.setPrimaryClip(
                                    ClipData.newPlainText(null, null)
                            );
                        }
                        if (isGotoFind) {
                            stateListener.onStateChanged(
                                    UWebView.this,
                                    stateListener.STATE_FIND_START, selText
                            );
                        } else {
                            showDict(selText);
                        }
                    }
                };
        int copyId = copyItem.getItemId();
        MenuItem.OnMenuItemClickListener listener = item -> {
            cm.addPrimaryClipChangedListener(clipListener);
            menu.performIdentifierAction(copyId, 0);
            isGotoFind = item.getTitle().toString().equalsIgnoreCase(
                    getResources().getString(R.string.find)
            );
            return false;
        };
        menu.add(getResources().getString(R.string.dict))
                .setOnMenuItemClickListener(listener);
        if (enabledFind) {
            menu.add(getResources().getString(R.string.find))
                    .setOnMenuItemClickListener(listener);
        }
    }

    /**
     * Dictionary window
     *
     * @param sourceText what need to translate.
     */
    private void showDict(CharSequence sourceText) {
        String url = "https://m.youdao.com/dict?le=eng&q=" + sourceText;
        Context context = getContext();
        View v = LayoutInflater.from(context).inflate(R.layout.dict, null);
        final UWebView tWebView = v.findViewById(R.id.uwv_dict);
        tWebView.enabledFind = false;
        WebSettings sets = tWebView.getSettings();
        sets.setUseWideViewPort(true);
        sets.setDatabaseEnabled(true);
        sets.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        sets.setBlockNetworkImage(!enabledDictJS);
        sets.setJavaScriptEnabled(enabledDictJS);
        tWebView.loadUrl(url);
        final CheckBox cb = v.findViewById(R.id.cb_dict_sj);
        cb.setChecked(enabledDictJS);
        cb.setOnCheckedChangeListener((checkBox, isChecked) -> {
            tWebView.getSettings().setJavaScriptEnabled(isChecked);
            tWebView.getSettings().setBlockNetworkImage(!isChecked);
            tWebView.reload();
        });
        final AlertDialog dialog = new AlertDialog.Builder(context)
                .setView(v).create();
        View.OnClickListener listener = v1 -> {
            int id = v1.getId();
            if (id == R.id.btn_dict_ok)
                dialog.dismiss();
            else if (id == R.id.btn_dict_prev)
                tWebView.goBack();
            else if (id == R.id.btn_dict_next)
                tWebView.goForward();
        };
        v.findViewById(R.id.btn_dict_ok).setOnClickListener(listener);
        v.findViewById(R.id.btn_dict_prev).setOnClickListener(listener);
        v.findViewById(R.id.btn_dict_next).setOnClickListener(listener);
        dialog.setOnDismissListener(p1 -> {
            if (cb.isChecked() != enabledDictJS) {
                enabledDictJS = !enabledDictJS;
                savePreferences();
            }
        });
        dialog.show();
        // 设置高度必须在dialog.show()后面，否正出错
        int sh = getResources().getDisplayMetrics().heightPixels;
        v.getLayoutParams().height = sh / 2;
    }

    public void setStateListener(StateListener stateListener) {
        this.stateListener = stateListener;
    }

    public StateListener getStateListener() {
        return stateListener;
    }

    public interface StateListener {
        // 状态监听接口
        int STATE_STARTED = 0;
        int STATE_FINISHED = 1;
        int STATE_PROGRESS = 2;
        int STATE_FIND_START = 3;
        int STATE_RECEIVED_TITLE = 4;

        void onStateChanged(WebView v, int stateType, Object... args);
    }
}
